﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace System.ComponentModel.DataAnnotations
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class ComparisonAttribute : ValidationAttribute
    {
        private const string _defaultErrorMessage = "'{0}' 和 '{1}' 不匹配。";
        private readonly object _typeId = new object();

        /// <summary>
        /// 比较两个值
        /// </summary>
        /// <param name="validProperty">要验证的属性</param>
        /// <param name="comparerProperty">要比较的属性</param>
        /// <param name="comparer">比较器</param>
        public ComparisonAttribute(string validProperty, string comparerProperty,ComparerOperator comparer)
            : base(_defaultErrorMessage)
        {
            ComparerProperty = validProperty;
            ValidProperty = comparerProperty;
            Operator = comparer;

            switch (comparer)
            { 
                case ComparerOperator.Equal:
                    Comparer = (p1, p2) => { if (p1 == null)return p2 == null; return p1.Equals(p2); };
                    break;
                case ComparerOperator.UnEqual:
                    Comparer = (p1, p2) => { if (p1 == null)return p2 != null; return !p1.Equals(p2); };
                    break;
                case ComparerOperator.GreaterThan:
                    Comparer = (p1, p2) => ((IComparable)p1).CompareTo((IComparable)p2) > 0;
                    break;
                case ComparerOperator.GreaterThanOrEqual:
                    Comparer = (p1, p2) => {  return ((IComparable)p1).CompareTo((IComparable)p2) >= 0; };
                    break;
                case ComparerOperator.LessThan:
                    Comparer = (p1, p2) => ((IComparable)p1).CompareTo((IComparable)p2) < 0;
                    break;
                case ComparerOperator.LessThanOrEqual:
                    Comparer = (p1, p2) => ((IComparable)p1).CompareTo((IComparable)p2) <= 0;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("comparer");
            }
        }

        public string ValidProperty { get; private set; }
        public string ComparerProperty { get; private set; }
        public Func<object, object, bool> Comparer { get; private set; }
        public ComparerOperator Operator { get; private set; }
        
        public override string FormatErrorMessage(string name)
        {
            return String.Format(ErrorMessageString,
                ComparerProperty, ValidProperty);
        }

        public override bool IsValid(object value)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
            object validProperty = properties.Find(ComparerProperty, true).GetValue(value);
            object comparerProperty = properties.Find(ValidProperty, true).GetValue(value);
            return Comparer(validProperty, comparerProperty);
        }
    }



    [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public sealed class CustomComparisonAttribute : ValidationAttribute
    {
        private const string _defaultErrorMessage = "'{0}' 和 '{1}' 不匹配。";
        private readonly object _typeId = new object();

        /// <summary>
        /// 比较两个值
        /// </summary>
        /// <param name="validProperty">要验证的属性</param>
        /// <param name="comparerProperty">要比较的属性</param>
        /// <param name="comparer">比较器</param>
        public CustomComparisonAttribute(ComparerDataType type,string comparerProperty, ComparerOperator comparer)
            : base(_defaultErrorMessage)
        {
            Type = type;
            ComparerProperty = comparerProperty;
            Operator = comparer;

        }

        public ComparerDataType Type { get; private set; }
        public string ComparerProperty { get; private set; }
        public ComparerOperator Operator { get; private set; }

        public override bool IsValid(object value)
        {
            return true;
        }
    }

    /// <summary>
    /// 指示要进行客户端比较验证
    /// </summary>
    public sealed class ComparisonValidator : DataAnnotationsModelValidator<CustomComparisonAttribute>
    {
        public ComparisonValidator(ModelMetadata metadata, ControllerContext context, CustomComparisonAttribute attribute)
            : base(metadata, context, attribute)
        {

        }

        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = base.ErrorMessage,
                ValidationType = "Comparison"
            };

            rule.ValidationParameters.Add("comparCol", base.Attribute.ComparerProperty);
            rule.ValidationParameters.Add("operator", (int)base.Attribute.Operator);
            rule.ValidationParameters.Add("datatype", (int)base.Attribute.Type);

            return new[] { rule };
        }
    
    }

    /// <summary>
    /// 指示客户端验证的数据类型
    /// </summary>
    public enum ComparerDataType
    { 
        /// <summary>
        /// 字符串
        /// </summary>
        String=1,
        /// <summary>
        /// 整数
        /// </summary>
        Integer=2,
        /// <summary>
        /// 双精度浮点型
        /// </summary>
        Double=3,
        /// <summary>
        /// 日期
        /// </summary>
        Date=4
    }

    /// <summary>
    /// 指示要用何种比较运算比较
    /// </summary>
    public enum ComparerOperator
    {
        /// <summary>
        /// "=" 等于
        /// </summary>
        Equal=1,
        /// <summary>
        /// "&lt;&gt;" 不等于
        /// </summary>
        UnEqual=2,
        /// <summary>
        /// 大于
        /// </summary>
        GreaterThan=3,
        /// <summary>
        /// "&gt;=" 大于等于
        /// </summary>
        GreaterThanOrEqual=4,
        /// <summary>
        /// "&lt;" 小于
        /// </summary>
        LessThan=5,
        /// <summary>
        /// "&lt;=" 小于等于
        /// </summary>
        LessThanOrEqual=6,
        /// <summary>
        /// 数据类型验证
        /// </summary>
        DateTypeCheck=7
    }

    public static class ComparerOperatorEx
    {
        /// <summary>
        /// 或取名称
        /// </summary>
        public static string GetName(this ComparerOperator _operator)
        {
            switch (_operator)
            { 
                case ComparerOperator.Equal:
                    return "等于";
                case ComparerOperator.UnEqual:
                    return "不等于";
                case ComparerOperator.GreaterThan:
                    return "大于";
                case ComparerOperator.GreaterThanOrEqual:
                    return "大于等于";
                case ComparerOperator.LessThan:
                    return "小于";
                case ComparerOperator.LessThanOrEqual:
                    return "小于等于";
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// 或取运算符
        /// </summary>
        public static string GetOperator(this ComparerOperator _operator)
        {
            switch (_operator)
            { 
                case ComparerOperator.Equal:
                    return "=";
                case ComparerOperator.UnEqual:
                    return "!=";
                case ComparerOperator.GreaterThan:
                    return ">";
                case ComparerOperator.GreaterThanOrEqual:
                    return ">=";
                case ComparerOperator.LessThan:
                    return "<";
                case ComparerOperator.LessThanOrEqual:
                    return "<=";
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}